package dao

import (
	"fmt"
	"gorm.io/gorm"
	"strings"
	"time"
	"yundian/internel/app/helper"
	"yundian/internel/app/helper/request"
	"yundian/internel/app/models/profit"
	"yundian/internel/app/models/users"
	"yundian/internel/pkg/dingo"
	"yundian/internel/pkg/dingo/global"
	"yundian/internel/pkg/utils"
)

// 获取商户用户列表
func (d *UserDao) GetPlaceUserList(param *request.UserList) *dingo.ErrorWrap {

	var (
		lst    []*users.UserInfoWithPlace
		count  int64
		limit  int = param.PageSize
		offset int = param.PageSize * (param.PageNo - 1)
	)

	//placeTypes := []int{helper.TypeNumIsPlaceAgent, helper.TypeNumIsPlaceEmployed}
	db := global.Orm.Debug().
		Table("users u").
		Select("u.*", "r.name as role_name").
		Joins("left join roles r on r.id = u.role_id").
		Joins("left join users parent on parent.id = u.parent_id").
		Where("u.is_delete = 0").
		Where("u.is_admin = ?", param.IsAdmin)
		//Where("u.is_place in ?", placeTypes)

	//db.Where("u.is_place = ?", 0) // isPlace = 2 已废弃

	if param.UserLoginIsAdmin != helper.TypeNumIsAdminOperator {
		userIdArr := NewUserDao().QueryChildUserIds(param.ParentId).Unwrap().([]int)
		userIdArr = append(userIdArr, param.ParentId)
		db.Where(" AND parent.id in ?", userIdArr)
	}

	if param.SearchText != "" {
		db.Where("u.user_name like ?", fmt.Sprint("%", param.SearchText, "%"))
	}
	if param.Name != "" {
		db.Where("u.name like ?", fmt.Sprint("%", param.Name, "%"))
	}
	if param.Phone != "" {
		db.Where("u.phone = ?", param.Phone)
	}
	if param.Status > 0 {
		db.Where("u.status = ?", param.Status)
	}

	if param.UserNo != "" {
		db.Where("u.user_no = ?", param.UserNo)
	}

	if param.IsTianHai > 0 {
		db.Where("u.is_tianhai = ?", param.IsTianHai)
	}

	// 时间查询
	if param.BeginTime != "" {
		beginTime := strings.Split(param.BeginTime, ",")
		db.Where("u.last_login_time >= ? and u.last_login_time <= ?", beginTime[0], beginTime[1])
	}

	// 排序
	if param.SortField != "" && param.SortOrder == "ascend" {
		db.Order(fmt.Sprintf("u.%s asc", utils.String(param.SortField).SnakeCase()))
	}
	if param.SortField != "" && param.SortOrder == "descend" {
		db.Order(fmt.Sprintf("u.%s desc", utils.String(param.SortField).SnakeCase()))
	}
	if param.SortField == "" {
		db.Order("u.create_at desc")
	}

	db.Limit(limit).Offset(offset).Find(&lst).Limit(-1).Offset(-1).Count(&count)

	return dingo.ErrorIf(db.Error, lst, count)

}

// 获取商户下级列表
func (d *UserDao) GetPlaceUserListByParentId(parentId int) *dingo.ErrorWrap {

	lst := make([]*users.UserInfoWithPlace, 0)
	sql := `select u.*,r.name as role_name from users u left join roles r on r.id = u.role_id where
u.parent_id = ? and u.is_admin = 3 and u.is_place = 1 and u.is_delete = 0`
	db := global.Orm.Debug().Raw(sql, parentId).Find(&lst)

	return dingo.ErrorIf(db.Error, lst)
}

// 获取商户列表
func (d *UserDao) GetPlaceUserListParentIds(userId []int, param *request.UserList) *dingo.ErrorWrap {

	var (
		lst    []*users.UserInfoWithPlace
		count  int64
		limit  int = param.PageSize
		offset int = param.PageSize * (param.PageNo - 1)
	)
	db := global.Orm.Debug().
		Table("users u").
		Select("u.*", "r.name as role_name").
		Joins("left join roles r on r.id = u.role_id")
	db.Where("u.is_delete = ?", 0)
	db.Where("u.is_admin = ?", 3)
	//db.Where("u.parent_id = ?", userId)
	db.Where("u.id in (?) ", userId)

	if param.SearchText != "" {
		db.Where("u.user_name like ?", fmt.Sprint("%", param.SearchText, "%"))
	}
	if param.Name != "" {
		db.Where("u.name like ?", fmt.Sprint("%", param.Name, "%"))
	}
	if param.Phone != "" {
		db.Where("u.phone = ?", param.Phone)
	}
	if param.Status > 0 {
		db.Where("u.status = ?", param.Status)
	}

	if param.UserNo != "" {
		db.Where("u.user_no = ?", param.UserNo)
	}

	// 时间查询
	if param.BeginTime != "" {
		beginTime := strings.Split(param.BeginTime, ",")
		db.Where("u.last_login_time >= ? and u.last_login_time <= ?", beginTime[0], beginTime[1])
	}

	// 排序
	if param.SortField != "" && param.SortOrder == "ascend" {
		db.Order(fmt.Sprintf("u.%s asc", utils.String(param.SortField).SnakeCase()))
	}
	if param.SortField != "" && param.SortOrder == "descend" {
		db.Order(fmt.Sprintf("u.%s desc", utils.String(param.SortField).SnakeCase()))
	}
	if param.SortField == "" {
		db.Order("u.create_at desc")
	}

	db.Limit(limit).Offset(offset).Find(&lst).Limit(-1).Offset(-1).Count(&count)

	return dingo.ErrorIf(db.Error, lst, count)
}

// InsertAgentUser 新增商户用户
func (d *UserDao) InsertPlaceUser(param *request.AdminUserInsertReq) *dingo.ErrorWrap {
	db := global.Orm.Debug()
	var m *users.UserModel
	err := db.Transaction(func(tx *gorm.DB) error {
		m = users.New().Mutate(
			users.WithCreateAt(dingo.Time(time.Now().Unix())),
			users.WithName(param.Name),
			users.WithUserName(param.UserName),
			users.WithNickName(param.UserName),
			users.WithPhone(param.Phone),
			users.WithPhoneCode("+86"),
			users.WithStatus(param.Status),
			users.WithPassword(utils.EncryptPassword(param.Password)),
			users.WithRoleId(param.RoleId),
			users.WithParentId(param.ParentId),

			//添加地址
			users.WithProvince(param.Province),
			users.WithCity(param.City),

			users.WithProfitType(param.ProfitType),
			users.WithProfitIsVisible(param.ProfitIsVisible),
			users.WithOrderIsVisible(param.OrderIsVisible),
			users.WithIncomeIsVisible(param.IncomeIsVisible),
			users.WithProfitProportion(param.ProfitProportion),
			users.WithSmProfitProportion(param.SmProfitProportion),
			users.WithUserNo("SH"+time.Now().Format("20060102150405")),
			users.WithBranchUserId(param.KaUserId),
			users.WithIsAdmin(3),
			users.WithIsPlace(1),
			users.WithIsCash(param.IsCash),
			users.WithIsDraw(param.IsDraw),
			users.WithTaxRate(param.TaxRate),
			users.WithIsDivinds(param.IsDivinds),
			users.WithIsSteward(param.IsSteward),
			users.WithModule(param.Module),
			users.WithPlatform(param.Platform),
		)
		if err := tx.Table("users").Create(&m).Error; err != nil {
			// 返回任何错误都会回滚事务
			return err
		}
		// 分成表 密码线 PCL - 暂时使用的是users表中的分成，后期有改动时再用这个
		p := profit.New().Mutate(
			profit.WithCreateAt(dingo.Time(time.Now().Unix())),
			profit.WithUserID(m.ID),
			profit.WithSharedMode("pcl"),
			profit.WithDeviceTypeId(10),
			profit.WithProfitType(1),
			profit.WithProfitIsVisible(param.ProfitIsVisible),
			profit.WithProfitProportion(param.ProfitProportion),
		)

		if err := tx.Debug().Table("profits").Create(&p).Error; err != nil {
			return err
		}

		// 分成表 售货机 sm - 暂时使用的是users表中的分成，后期有改动时再用这个
		p2 := profit.New().Mutate(
			profit.WithCreateAt(dingo.Time(time.Now().Unix())),
			profit.WithUserID(m.ID),
			profit.WithSharedMode("cdb"),
			profit.WithDeviceTypeId(11),
			profit.WithProfitType(1),
			profit.WithProfitIsVisible(param.ProfitIsVisible),
			profit.WithProfitProportion(param.SmProfitProportion),
		)

		if db := tx.Debug().Table("profits").Create(&p2); db.Error != nil {
			return db.Error
		}

		// 返回 nil 提交事务
		return nil
	})
	return dingo.ErrorIf(err, m.ID)
}

// UpdateAgentUser 修改商户用户
func (d *UserDao) UpdatePlaceUser(param *request.AdminUserInsertReq) *dingo.ErrorWrap {
	err := global.Orm.Transaction(func(tx *gorm.DB) error {
		//m := users.New().Mutate(
		//	users.WithUpdateAt(dingo.Time(time.Now().Unix())),
		//	users.WithRoleId(param.RoleId),
		//	users.WithParentId(param.ParentId),
		//
		//	users.WithPhone(param.Phone),
		//	users.WithUserName(param.UserName),
		//	users.WithName(param.Name),
		//	users.WithProfitProportion(param.ProfitProportion),
		//	users.WithSmProfitProportion(param.SmProfitProportion),
		//	users.WithTaxRate(param.TaxRate),
		//	users.WithIsDivinds(param.IsDivinds),
		//	users.WithProfitIsVisible(param.ProfitIsVisible),
		//	users.WithIsCash(param.IsCash),
		//	users.WithStatus(param.Status),
		//	users.WithModule(param.Module),
		//)
		m := map[string]interface{}{
			"update_at":             dingo.Time(time.Now().Unix()),
			"parent_id":             param.ParentId,
			"phone":                 param.Phone,
			"name":                  param.Name,
			"user_name":             param.UserName,
			"profit_proportion":     param.ProfitProportion,
			"sm_profit_proportion":  param.SmProfitProportion,
			"is_cash":               param.IsCash,
			"is_divinds":            param.IsDivinds,
			"profit_is_visible":     param.ProfitIsVisible,
			"status":                param.Status,
			"module":                param.Module,
		}
		tx.Debug().Table("users").Where("id = ? AND id<>?", param.Id, param.ParentId).Model(&m).Updates(m)
		if err := tx.Error; err != nil {
			// 返回任何错误都会回滚事务
			return err
		}

		// 分成表 密码线 PCL - 暂时使用的是users表中的分成，后期有改动时再用这个
		p := profit.New().Mutate(
			profit.WithUpdateAt(dingo.Time(time.Now().Unix())),
			profit.WithUserID(param.Id),
			profit.WithProfitProportion(param.ProfitProportion),
		)
		tx.Debug().Table("profits").
			Where("user_id = ?", param.Id).
			Where("shared_mode = ?", "pcl").Model(&p).Updates(p)
		if err := tx.Error; err != nil {
			return err
		}

		// 分成表 售货机 sm - 暂时使用的是users表中的分成，后期有改动时再用这个
		p2 := profit.New().Mutate(
			profit.WithUpdateAt(dingo.Time(time.Now().Unix())),
			profit.WithUserID(param.Id),
			profit.WithProfitProportion(param.SmProfitProportion),
		)
		tx.Debug().Table("profits").
			Where("user_id = ?", param.Id).
			Where("shared_mode = ?", "cdb").Model(&p2).Updates(p2)
		if err := tx.Error; err != nil {
			return err
		}

		// 返回 nil 提交事务
		return nil
	})

	return dingo.ErrorIf(err, true)
}

// InsertBdUser 新增BD用户
func (d *UserDao) InsertBdUser(param *request.AdminUserInsertReq) *dingo.ErrorWrap {
	db := global.Orm
	var m *users.UserModel

	m = users.New().Mutate(
		users.WithCreateAt(dingo.Time(time.Now().Unix())),
		users.WithName(param.Name),
		users.WithUserName("BD" + param.Name),
		users.WithPhone(param.Phone),
		users.WithPhoneCode("+86"),
		users.WithStatus(param.Status),
		users.WithPassword(utils.EncryptPassword(param.Password)),

		users.WithParentId(param.ParentId),
		users.WithIsDraw(param.IsDraw),
		users.WithIncomeIsVisible(param.IncomeIsVisible),
		users.WithOrderIsVisible(param.OrderIsVisible),
		users.WithProfitIsVisible(param.ProfitIsVisible),
		users.WithProfitProportion(param.ProfitProportion),
		users.WithSmProfitProportion(param.SmProfitProportion),
		users.WithTaxRate(param.TaxRate),
		users.WithIsDivinds(param.IsDivinds),
		users.WithIsDividendsSm(param.IsDividendsSm),
		users.WithIsCash(param.IsCash),
		users.WithRoleId(param.RoleId),
		users.WithIsSteward(param.IsSteward),

		users.WithIsAdmin(9),
		users.WithModule(param.Module),

		users.WithUserNo("BD"+time.Now().Format("20060102150405")),
		users.WithPlatform(param.Platform),
	)
	db.Debug().Table("users").Create(&m)
	return dingo.ErrorIf(db.Error, m.ID)
}

// UpdateBdUser 修改BD用户
func (d *UserDao) UpdateBdUser(param *request.AdminUserInsertReq) *dingo.ErrorWrap {
	db := global.Orm
	m := users.New().Mutate(
		users.WithUpdateAt(dingo.Time(time.Now().Unix())),
		users.WithParentId(param.ParentId),

		users.WithPhone(param.Phone),
		users.WithUserName(param.UserName),
		users.WithName(param.Name),
		users.WithProfitProportion(param.ProfitProportion),
		users.WithSmProfitProportion(param.SmProfitProportion),
		users.WithIsDivinds(param.IsDivinds),
		users.WithIsDividendsSm(param.IsDividendsSm),
		users.WithProfitIsVisible(param.ProfitIsVisible),
		users.WithIsCash(param.IsCash),
		users.WithStatus(param.Status),
		users.WithModule(param.Module),
	)

	db.Debug().Table("users").Where("id = ? AND id<>?", param.Id, param.ParentId).Model(&m).Updates(m)

	return dingo.ErrorIf(db.Error, true)
}

// InsertBdUser 新增子帐号
func (d *UserDao) InsertChildUser(param *request.AdminUserInsertReq) *dingo.ErrorWrap {
	db := global.Orm
	var m *users.UserModel

	m = users.New().Mutate(
		users.WithCreateAt(dingo.Time(time.Now().Unix())),
		users.WithName(param.Name),
		users.WithUserName("ZC" + param.Name),
		users.WithPhone(param.Phone),
		users.WithPhoneCode("+86"),
		users.WithStatus(param.Status),
		users.WithPassword(utils.EncryptPassword(param.Password)),

		users.WithParentId(param.ParentId),
		users.WithIsDraw(param.IsDraw),
		users.WithIncomeIsVisible(param.IncomeIsVisible),
		users.WithOrderIsVisible(param.OrderIsVisible),
		users.WithProfitIsVisible(param.ProfitIsVisible),
		users.WithProfitProportion(param.ProfitProportion),
		users.WithSmProfitProportion(param.SmProfitProportion),
		users.WithTaxRate(param.TaxRate),
		users.WithIsDivinds(param.IsDivinds),
		users.WithIsCash(param.IsCash),
		users.WithRoleId(param.RoleId),
		users.WithIsSteward(param.IsSteward),

		users.WithIsAdmin(4),
		users.WithModule(param.Module),

		users.WithUserNo("ZC"+time.Now().Format("20060102150405")),
	)
	db.Debug().Table("users").Create(&m)
	return dingo.ErrorIf(db.Error, m.ID)
}

// UpdateBdUser 修改子帐号
func (d *UserDao) UpdateChildUser(param *request.AdminUserInsertReq) *dingo.ErrorWrap {
	db := global.Orm
	m := users.New().Mutate(
		users.WithUpdateAt(dingo.Time(time.Now().Unix())),
		users.WithRoleId(param.RoleId),
		users.WithParentId(param.ParentId),

		users.WithPhone(param.Phone),
		users.WithUserName(param.UserName),
		users.WithName(param.Name),
		users.WithProfitProportion(param.ProfitProportion),
		users.WithSmProfitProportion(param.SmProfitProportion),
		users.WithTaxRate(param.TaxRate),
		users.WithIsDivinds(param.IsDivinds),
		users.WithProfitIsVisible(param.ProfitIsVisible),
		users.WithIsCash(param.IsCash),
		users.WithStatus(param.Status),
		users.WithModule(param.Module),
	)

	db.Debug().Table("users").Where("id = ? AND id<>?", param.Id, param.ParentId).Model(&m).Updates(m)

	return dingo.ErrorIf(db.Error, true)
}

func (d *UserDao) CountPlaceUserByParentId(parentId int) *dingo.ErrorWrap {

	var total int64
	sql := `select count(1) from users where is_place = 1 and is_admin = 3 and parent_id = ?`
	db := global.Orm.Debug().Raw(sql, parentId).Find(&total)

	return dingo.ErrorIf(db.Error, total)
}

func (d *UserDao) GetPlaceBranchUserId() *dingo.ErrorWrap {
	var ids []int

	sql := `select id from users where is_place = 5  `
	db := global.Orm.Debug().Raw(sql).Find(&ids)
	return dingo.ErrorIf(db.Error, ids)
}

func (d *UserDao) GetUserIdByPlaceId(placeIds []int) *dingo.ErrorWrap {
	var ids []int

	sql := `select user_id from places where id in (?)`
	db := global.Orm.Debug().Raw(sql, placeIds).Find(&ids)
	return dingo.ErrorIf(db.Error, ids)
}

func (d *UserDao) GetByPlaceIdBranchUserId(placeIds int) *dingo.ErrorWrap {
	var ids []int

	sql := `select user_id from places where branch_user_id = ?`
	db := global.Orm.Debug().Raw(sql, placeIds).Find(&ids)
	return dingo.ErrorIf(db.Error, ids)
}

func (d *UserDao) UpdateUserBranchUserId(ids []int, m *users.UserModel) *dingo.ErrorWrap {

	db := global.Orm.Debug().Table("users").Select("branch_user_id").Where("id in (?)", ids).Model(&m).Updates(m)
	return dingo.ErrorIf(db.Error, true)
}
